home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch05 / adapt.old < prev    next >
Text File  |  1994-06-02  |  37KB  |  891 lines

  1. /*...................... ADAPT.C .................. 6-3-94 ....*/
  2. /* This program demonstrates Adaptive Color Palette generation.*/
  3. /* It reads True Color (24 bit per pixel) TARGA images and     */
  4. /* converts them to 8 bit palette images. It also writes out   */
  5. /* the converted image as an 8 bit per pixel Palette Color TIFF*/
  6. /* image.                                                      */
  7. /*.............................................................*/
  8.  
  9. #include<malloc.h>
  10. #include<stdlib.h>
  11. #include <stdio.h>
  12. #include <fcntl.h>
  13. #include <io.h>
  14. #include<conio.h>
  15. #include <math.h>
  16. #include<tiff.h>
  17. #include<vsa.h>
  18.  
  19. /*.............................................................*/
  20. /*       Define type struct CUBE first, needed later!          */
  21. /*.............................................................*/
  22. struct CUBE {
  23.     unsigned x0;
  24.     unsigned y0;
  25.     unsigned z0;
  26.     unsigned x1;    // Outside of cube volume!
  27.     unsigned y1;    // Outside of cube volume!
  28.     unsigned z1;    // Outside of cube volume!
  29.     unsigned vol;   // this is the volume of the cube;
  30.     long r_avg;     // this is the Average Red value for cube
  31.     long g_avg;     // this is the Average Green value for cube
  32.     long b_avg;     // this is the Average Blue value for cube
  33.     long fsum;      // this is the sum of frequencies in cube
  34.     long cerr;      // this is the NET color error for the cube
  35.     float fom;      // Figure Of Merit, Worthyness of cube split
  36.   };
  37.  
  38. /*.............................................................*/
  39. /*     All of the function prototypes.                         */
  40. /*.............................................................*/
  41. int  adaptive_lut(char *,unsigned char far *,
  42.                   unsigned char far *);
  43. int  volume_hist(char *, unsigned char far *);
  44. void analyze_row(unsigned char far *, int, unsigned char far *);
  45. void bisect_cube(struct CUBE far *,struct CUBE far *);
  46. void gen_cube_color_stats(struct CUBE far *,
  47.                           unsigned char far *,int);
  48. void validate_cube(struct CUBE far *);
  49. void copy_cube(struct CUBE, struct CUBE far *);
  50. int  add_cube_to_list(struct CUBE, int);
  51. int  delete_cube_from_list(int, int);
  52. int  move_cubes_to_lut(int, unsigned char far *,
  53.                        unsigned char far *);
  54. void assign_lut_to_colors(unsigned char far *, unsigned);
  55. void replace_pixel(unsigned char *, unsigned, unsigned char *);
  56. void set_adaptive_config(int, int, int);
  57. void get_adaptive_config(int far *, int far *, int far *);
  58. unsigned long read_tga_header(int, int *, int *, int *, int *);
  59. void true_color_lut(void);
  60.  
  61. /*.............................................................*/
  62. /*     Global variables which control the show.                */
  63. /*.............................................................*/
  64. int ADPTV_MODE = 0;                 /*..   Default = 0 (Off) ..*/
  65. int ADPTV_NUM_COLORS = 256;         /*..   Default = 256     ..*/
  66. int ADPTV_QUALITY = 50;             /*..   Default = 50      ..*/
  67. struct CUBE CUBE_LIST[256];
  68.  
  69. #define ADPTV_ASSIGN_MODE  0        /*.. This is experimental..*/
  70.  
  71. void main()
  72. {
  73.   char filename[80];
  74.   int i,j,size,width,height,type,file_handle,orient, colors;
  75.   unsigned char lut[768], rgb[3072], far *vhist;
  76. /*.............................................................*/
  77. /* Set up the Adaptive Palette controls and get the TARGA      */
  78. /* image file name.                                            */
  79. /*.............................................................*/
  80.   set_adaptive_config(1,256,50);
  81. LOOP:
  82.   printf("Input TARGA Image Filename: ");
  83.   scanf("%s",filename);
  84. /*.............................................................*/
  85. /* Allocate memory for the Volume Histogram.  Then run the     */
  86. /* Adaptive Palette code to generate the adaptive palette.     */
  87. /*.............................................................*/
  88.     if(ADPTV_MODE)
  89.         {
  90.             printf("\n");
  91.             printf("Please Wait, Computing Adaptive Color Palette.\n");
  92.             printf("\n");
  93.             if((vhist = (unsigned char far *)halloc(32768,1)) == NULL)
  94.                 {
  95.                     printf("Can't Allocate Memory for Histogram!\n");
  96.                     return;
  97.                 }
  98.             colors = adaptive_lut(filename,vhist,lut);
  99.         }
  100. /*.............................................................*/
  101. /*            Set highest video resolution available.          */
  102. /*.............................................................*/
  103.     if(vsa_init(0x2105) != 0)                /* 1024 x 768 x 256 */
  104.         if(vsa_init(0x2103) != 0)              /*  800 x 600 x 256 */
  105.             if(vsa_init(0x2101) != 0)            /*  640 x 480 x 256 */
  106.                 if(vsa_init(0x2100) != 0)          /*  640 x 400 x 256 */
  107.                     {
  108.                         printf("Can't set VESA video mode\n");
  109.                         printf("Is VESA BIOS Extension TSR loaded?\n");
  110.                         return;
  111.                     }
  112. /*.............................................................*/
  113. /* Set up Color Palette either to Adaptive Palette or 8 bit RGB*/
  114. /*.............................................................*/
  115.     if(ADPTV_MODE)
  116.         vsa_write_color_block(0,colors,lut);
  117.     else
  118.         true_color_lut();
  119. /*.............................................................*/
  120. /*           Open the TARGA file and get header info.          */
  121. /*.............................................................*/
  122.   if((file_handle = open(filename,O_BINARY | O_RDONLY)) == -1)
  123.     return;
  124.   read_tga_header(file_handle,&width,&height,&type,&orient);
  125. /*.............................................................*/
  126. /* Depending on orientation, read file out-top down or         */
  127. /* bottom-up, replace 24 bit pixels with 8 bit palette indexes,*/
  128. /* and display on screen.                                      */
  129. /*.............................................................*/
  130.   if(orient == 32)
  131.     for(j=0;j<height;j++)
  132.       {
  133.         read(file_handle,rgb,3*width);
  134.         replace_pixel(rgb,width,vhist);
  135.         vsa_raster_line(0,width-1,j,rgb);
  136.       }
  137.   else
  138.     for(j=height-1;j>=0;j--)
  139.       {
  140.         read(file_handle,rgb,3*width);
  141.         replace_pixel(rgb,width,vhist);
  142.         vsa_raster_line(0,width-1,j,rgb);
  143.       }
  144. /*.............................................................*/
  145. /*  Close the image file and look for an ESC key to quit.      */
  146. /*  Otherwise, save new image as an 8 bit TIFF called          */
  147. /*  NEW.TIF and LOOP for experimentation with a different      */
  148. /*  input image files.                                         */
  149. /*.............................................................*/
  150.   if(ADPTV_MODE)
  151.     hfree((unsigned char huge *)vhist);
  152.   close(file_handle);
  153.   if(getch() == 27)
  154.     goto SKIP;
  155.   tf_save_file(0,0,width-1,height-1,"new.tif");
  156.   vsa_set_svga_mode(0x3);
  157.   goto LOOP;
  158. SKIP:
  159.   vsa_set_svga_mode(0x3);
  160.   return;
  161. }                               /*.....       End MAIN    .....*/
  162.  
  163.  
  164. /*....................... READ_TGA_HEADER  ....... 5-17-94 ....*/
  165. /* This routine parses through a TGA header and returns the    */
  166. /* file offset in bytes to the first byte of pixel data.       */
  167. /* It also returns image width, height, and type (type 2 is the*/
  168. /* uncompressed 24 bit image type).                            */
  169. /*.............................................................*/
  170. unsigned long read_tga_header(int handle, int *width,
  171.                               int *height, int *type,
  172.                               int *orientation)
  173. {
  174.   unsigned long offset;
  175.   unsigned char buff[18];
  176.   read(handle,buff,18);
  177.   offset = 18+buff[0];
  178.   *type = buff[2];
  179.  
  180.   *width  = *((unsigned *)buff + 6);
  181.   *height = *((unsigned *)buff + 7);
  182.   *orientation = buff[17];
  183.   return offset;
  184. }                           /*.... END read_tga_header    .....*/
  185.  
  186.  
  187. /*..................... ADAPTIVE_LUT ............ 5-31-94 .....*/
  188. /*    This routine analyzes the True Color image that is       */
  189. /*  defined in the TARGA file called 'filename' and computes   */
  190. /*  an Adpative Color Palette which is an optimal selection of */
  191. /*  the 256 colors for this particular image.  Before calling  */
  192. /*  this routine, 'array' must have been allocated 32768 bytes!*/
  193. /*    First a 32x32x32 volume histogram is computed.  Then the */
  194. /*  volume histogram "cube" is subdivide into up to 255 cubes  */
  195. /*  (color clusters) used in the image.  One more cube in this */
  196. /*  collection is always reserved for BLACK, in RGB space,     */
  197. /*  (this is done so that images which have few colors will    */
  198. /*  still get a good solid BLACK color in the CLUT). Finally   */
  199. /*  it assigns each one of the cubes to each one of the up to  */
  200. /*  256 palette entries, and returns the new Color Look Up     */
  201. /*  Table in the 'color_array'. The function return value is   */
  202. /*  the number of colors in the 'color_array' and is always    */
  203. /*  equal to 256 for now (unused colors set to black).         */
  204. /*    Upon completion, the 32k elements of 'array' store the   */
  205. /*  palette index for their respective true color value (down  */
  206. /*  converted to 15 bits).                                     */
  207. /*.............................................................*/
  208. int  adaptive_lut(char *filename,unsigned char *array,
  209.                   unsigned char *color_array)
  210. {
  211.   int num_cubes,num_vol,colors,most_cubes;
  212.   struct CUBE cube,new_cube;
  213.   most_cubes = ADPTV_NUM_COLORS-1;
  214.   num_cubes = 0;
  215.   VOLUME_HIST(filename,array);
  216. /*.............................................................*/
  217. /* Set up the number of cubes to be generated based on uniform */
  218. /* color VOLUME partitioning.  Then, the rest of the cubes are */
  219. /* generated on COLOR ERROR minimizing criteria.               */
  220. /*.............................................................*/
  221.   num_vol = (ADPTV_QUALITY * most_cubes) / 100;
  222. /*.............................................................*/
  223. /*  Initialize first cube.  Get its color stats and put it in  */
  224. /*  cube list.                                                 */
  225. /*.............................................................*/
  226.   if(most_cubes > 0)
  227.     {
  228.       cube.x0 = 0;
  229.       cube.y0 = 0;
  230.       cube.z0 = 0;
  231.       cube.x1 = 32;
  232.       cube.y1 = 32;
  233.       cube.z1 = 32;
  234.       gen_cube_color_stats(&cube,array,1);
  235.       num_cubes = add_cube_to_list(cube,num_cubes);
  236.     }
  237. /*.............................................................*/
  238. /*    Subdivide color volume based on minimizing cube Volumes. */
  239. /*    Do for 'num_vol' cubes.                                  */
  240. /*.............................................................*/
  241.   while(num_cubes < num_vol)
  242.     {
  243.       if(CUBE_LIST[0].vol <= 1)
  244.         break;
  245.       copy_cube(CUBE_LIST[0],&cube);
  246.       bisect_cube(&cube,&new_cube);
  247.       gen_cube_color_stats(&cube,array,1);
  248.       gen_cube_color_stats(&new_cube,array,1);
  249.       num_cubes = delete_cube_from_list(0,num_cubes);
  250.       if(cube.fsum != 0)
  251.         num_cubes = add_cube_to_list(cube,num_cubes);
  252.       if(new_cube.fsum != 0)
  253.         num_cubes = add_cube_to_list(new_cube,num_cubes);
  254.     }
  255. /*.............................................................*/
  256. /* Continue subdividing color volume based on minimizing cube  */
  257. /* color errors.  Do for remaining cubes (up to                */
  258. /* 'ADPTV_NUM_COLORS' - 1).                                    */
  259. /*.............................................................*/
  260.   while(num_cubes < most_cubes)
  261.     {
  262.       if(CUBE_LIST[0].vol <= 1)
  263.         break;
  264.       copy_cube(CUBE_LIST[0],&cube);
  265.       bisect_cube(&cube,&new_cube);
  266.       gen_cube_color_stats(&cube,array,2);
  267.       gen_cube_color_stats(&new_cube,array,2);
  268.       num_cubes = delete_cube_from_list(0,num_cubes);
  269.       if(cube.fsum != 0)
  270.         num_cubes = add_cube_to_list(cube,num_cubes);
  271.       if(new_cube.fsum != 0)
  272.         num_cubes = add_cube_to_list(new_cube,num_cubes);
  273.     }
  274. /*.............................................................*/
  275. /* Add last cube which is BLACK.    Force this cube to top of  */
  276. /* list (via cube.fom = 1000000000) so that it will end up at  */
  277. /* CLUT location 0.                                            */
  278. /*.............................................................*/
  279.   cube.x0 = 0;
  280.   cube.y0 = 0;
  281.   cube.z0 = 0;
  282.   cube.x1 = 1;
  283.   cube.y1 = 1;
  284.   cube.z1 = 1;
  285.   gen_cube_color_stats(&cube,array,1);
  286.   cube.fom = 1000000000.0;
  287.   num_cubes = add_cube_to_list(cube,num_cubes);
  288. /*.............................................................*/
  289. /* Finally, figure out the values for the Color Look Up table. */
  290. /*.............................................................*/
  291.   colors = move_cubes_to_lut(num_cubes,array,color_array);
  292.   return colors;
  293. }                              /*.....  End adaptive_lut  .....*/
  294.  
  295.  
  296. /*.......................... VOLUME_HIST ......... 5-31-94 ....*/
  297. /* This routine analyzes a True Color TARGA image file called  */
  298. /* 'filename' and generates a 3D R-G-B Volume Histogram which  */
  299. /* has 32 elements on a side (32 x 32 x 32). The histogram is  */
  300. /* returned in 'vhist[]'.  Each element of 'vhist[]' stores a  */
  301. /* count from 0 to 255 which is the frequency of occurance for */
  302. /* that color in the image. The count "saturates" at 255.      */
  303. /* ("That color" means the value indexing 'vhist') The value   */
  304. /* indexing 'vhist' is a 15 bit color value whos 5 MSBs are    */
  305. /* Red, then 5 bits Green and finally 5 LSBs of Blue. If the   */
  306. /* image file is not found, this routine returns with a error  */
  307. /* value of 1, else 0.                                         */
  308. /*.............................................................*/
  309. int  VOLUME_HIST(char *filename, unsigned char far *vhist)
  310. {
  311.   unsigned i;
  312.   int j,width,height,type,file_handle,orient;
  313.   unsigned char rgb[3072];
  314. /*.............................................................*/
  315. /*   Initialize 32x32x32 R-G-B historgram to all zeros.        */
  316. /*.............................................................*/
  317.   for(i=0;i<32768;i++)
  318.     vhist[i] = 0;
  319. /*.............................................................*/
  320. /*           Open the TARGA file and get header info.          */
  321. /*.............................................................*/
  322.   if((file_handle = open(filename,O_BINARY | O_RDONLY)) == -1)
  323.     return 1;
  324.   read_tga_header(file_handle,&width,&height,&type,&orient);
  325. /*.............................................................*/
  326. /*  Read out pixels from TARGA file and process in             */
  327. /*  top down or bottom up order depending on orientation.      */
  328. /*.............................................................*/
  329.   if(orient == 32)
  330.     for(j=0;j<height;j++)
  331.       {
  332.         read(file_handle,rgb,3*width);
  333.         analyze_row(rgb,width,vhist);
  334.       }
  335.   else
  336.     for(j=height-1;j>=0;j--)
  337.       {
  338.         read(file_handle,rgb,3*width);
  339.         analyze_row(rgb,width,vhist);
  340.       }
  341. /*.............................................................*/
  342. /*                   Close the image file.                     */
  343. /*.............................................................*/
  344.   close(file_handle);
  345.   return 0;
  346. }                                /*..... End VOLUME_HIST  .....*/
  347.  
  348.  
  349. /*.................... ANALYZE_ROW ............... 5-31-94 ....*/
  350. /*  This routine takes the pixel data for one row of a 24      */
  351. /*  bit/pixel image and accumulates data in the 32x32x32 R-G-B */
  352. /*  histogram 'vhist'. The pixel data is sent in the 'byte_buf'*/
  353. /*  array.  The number of pixels in the array is defined by    */
  354. /*  'width'.                                                   */
  355. /*.............................................................*/
  356. void  analyze_row(byte_buf,width,vhist)
  357. unsigned char far *byte_buf,far *vhist;
  358. int width;
  359. {
  360.   unsigned sum,i;
  361.   for(i=0;i<width;i++)
  362.     {
  363.       sum = 0;
  364.       sum += (byte_buf[3*i+2])/8 << 10;              /* RED    */
  365.       sum += (byte_buf[3*i+1])/8 << 5;               /* GREEN  */
  366.       sum += (byte_buf[3*i]  )/8;                    /* BLUE   */
  367.       if(vhist[sum] != 255)
  368.         vhist[sum]++;
  369.     }
  370.   return;
  371. }                                /*..... End analyze_row ......*/
  372.  
  373.  
  374. /*........................ BISECT_CUBE ............ 6-1-94 ....*/
  375. /* Input cube in 'cube', output two cubes in 'cube' and        */
  376. /* 'new_cube'.  Cubes are split along longest axis.  New cube  */
  377. /* guaranteed to be "validated".                               */
  378. /*.............................................................*/
  379. void  bisect_cube(struct CUBE *pcube,struct CUBE *pnew_cube)
  380. {
  381.   unsigned dx,dy,dz;
  382.   validate_cube(pcube);
  383. /*.............................................................*/
  384. /*             Get red, green, and blue extent of cube.        */
  385. /*.............................................................*/
  386.   dx = pcube->x1-pcube->x0;                 /* RED dimension   */
  387.   dy = pcube->y1-pcube->y0;                 /* GREEN dimension */
  388.   dz = pcube->z1-pcube->z0;                 /* BLUE dimension  */
  389. /*.............................................................*/
  390. /* If red is longest dimension, split red axis of cube.        */
  391. /*.............................................................*/
  392.   if((dx >= dy) && (dx >= dz))
  393.     {
  394.       pnew_cube->x0 = (pcube->x1 + pcube->x0)/2;
  395.       pnew_cube->y0 = pcube->y0;
  396.       pnew_cube->z0 = pcube->z0;
  397.       pnew_cube->x1 = pcube->x1;
  398.       pnew_cube->y1 = pcube->y1;
  399.       pnew_cube->z1 = pcube->z1;
  400.       pcube->x1 = pnew_cube->x0;
  401.       return;
  402.     }
  403. /*.............................................................*/
  404. /* If green is longest dimension, split green axis of cube.    */
  405. /*.............................................................*/
  406.   if((dy >= dx) && (dy >= dz))
  407.     {
  408.       pnew_cube->x0 = pcube->x0;
  409.       pnew_cube->y0 = (pcube->y1 + pcube->y0)/2;
  410.       pnew_cube->z0 = pcube->z0;
  411.       pnew_cube->x1 = pcube->x1;
  412.       pnew_cube->y1 = pcube->y1;
  413.       pnew_cube->z1 = pcube->z1;
  414.       pcube->y1 = pnew_cube->y0;
  415.       return;
  416.     }
  417. /*.............................................................*/
  418. /* If blue is longest dimension, split blue axis of cube.      */
  419. /*.............................................................*/
  420.   if((dz >= dx) && (dz >= dy))
  421.     {
  422.       pnew_cube->x0 = pcube->x0;
  423.       pnew_cube->y0 = pcube->y0;
  424.       pnew_cube->z0 = (pcube->z1 + pcube->z0)/2;
  425.       pnew_cube->x1 = pcube->x1;
  426.       pnew_cube->y1 = pcube->y1;
  427.       pnew_cube->z1 = pcube->z1;
  428.       pcube->z1 = pnew_cube->z0;
  429.       return;
  430.     }
  431. }                                 /*.... END: bisect_cube .....*/
  432.  
  433.  
  434. /*................. GEN_CUBE_COLOR_STATS ........... 6-1-94 ...*/
  435. /* Compute cube's color statistics (Volume, Frequency Sum,     */
  436. /* Average Color value for Red, Green, and Blue, Color Error,  */
  437. /* and Figure-Of-Merit).  The color error is the sum of        */
  438. /* ABS(color - avg_color)*frequency (sort of) for each color   */
  439. /* in cube.                                                    */
  440. /*.............................................................*/
  441. void  gen_cube_color_stats(struct CUBE *pcube,
  442.                            unsigned char *array,int mode)
  443. {
  444.   unsigned i,j,k,freq;
  445.   int dr,dg,db;
  446.   unsigned long sum,index,index0,color_error;
  447.   long red_avg,grn_avg,blu_avg;
  448.   sum = 0;
  449.   red_avg = 0;
  450.   grn_avg = 0;
  451.   blu_avg = 0;
  452.   color_error = 0;
  453. /*.............................................................*/
  454. /*                        Compute cube's volume                */
  455. /*.............................................................*/
  456.   pcube->vol = (pcube->x1-pcube->x0)*
  457.                (pcube->y1-pcube->y0)*
  458.                (pcube->z1-pcube->z0);
  459. /*.............................................................*/
  460. /*     Compute average red, green and blue values.             */
  461. /*.............................................................*/
  462.   for(k=pcube->x0;k<pcube->x1;k++)
  463.     {
  464.       index0 = k<<10;
  465.       for(j=pcube->y0;j<pcube->y1;j++)
  466.         {
  467.           index = index0 + (j<<5) + pcube->z0;
  468.           for(i=pcube->z0;i<pcube->z1;i++)
  469.             {
  470.               freq = array[index];
  471.               red_avg += k*freq;
  472.               grn_avg += j*freq;
  473.               blu_avg += i*freq;
  474.               sum += freq;
  475.               index ++;
  476.             }
  477.         }
  478.     }
  479.   if(sum != 0)
  480.     {
  481.       red_avg /= sum;
  482.       grn_avg /= sum;
  483.       blu_avg /= sum;
  484.     }
  485.   else
  486.     {
  487.       red_avg = 0;
  488.       grn_avg = 0;
  489.       blu_avg = 0;
  490.     }
  491. /*.............................................................*/
  492. /*     Now compute color error.                                */
  493. /*.............................................................*/
  494.   for(k=pcube->x0;k<pcube->x1;k++)
  495.     {
  496.       index0 = k<<10;
  497.       for(j=pcube->y0;j<pcube->y1;j++)
  498.         {
  499.           index = index0 + (j<<5) + pcube->z0;
  500.           for(i=pcube->z0;i<pcube->z1;i++)
  501.             {
  502.               freq = array[index];
  503.               dr = (red_avg-(int)k);
  504.               dg = (grn_avg-(int)j);
  505.               db = (blu_avg-(int)i);
  506.               color_error += freq*sqrt(dr*dr+dg*dg+db*db);
  507.               index ++;
  508.             }
  509.         }
  510.     }
  511.   pcube->r_avg = red_avg;
  512.   pcube->g_avg = grn_avg;
  513.   pcube->b_avg = blu_avg;
  514.   pcube->fsum  = sum;
  515.   pcube->cerr  = color_error;
  516. /*.............................................................*/
  517. /* You can decide what characteristic is used for the Figure of*/
  518. /* Merit (FOM) by setting 'mode' to 1 - 5.   Modes 1 and 2 are */
  519. /* normally used.  Modes 3, 4, and 5 are for play.             */
  520. /*.............................................................*/
  521.   if(mode == 1)
  522.     pcube->fom  = (float) pcube->vol;
  523.   if(mode == 2)
  524.     pcube->fom  = (float) pcube->cerr;
  525.   if(mode == 3)
  526.     pcube->fom  = (float) pcube->fsum;
  527.   if(mode == 4)
  528.     pcube->fom  = (float)(pcube->cerr)*(float)(pcube->fsum);
  529.   if(mode >= 5)
  530.     pcube->fom  = (float)(pcube->vol-1)*(float)(pcube->fsum);
  531.   return;
  532. }                         /*.... END: gen_cube_color_stats ....*/
  533.  
  534.  
  535. /*.................. MOVE_CUBES_TO_LUT ............ 6-3-94 ....*/
  536. /* This routine loads 'color_array' with the colors of the     */
  537. /* cubes in the 'CUBE_LIST' (after the 'CUBE_LIST' has been    */
  538. /* generated).  The return value is the number of colors       */
  539. /* loaded into 'color_array', and is always 256.               */
  540. /*.............................................................*/
  541. int  move_cubes_to_lut(int num_cubes,unsigned char *array,
  542.                        unsigned char *color_array)
  543. {
  544.   unsigned i;
  545. /*.............................................................*/
  546. /* Compute Color Lookup Table entries. You could do this by    */
  547. /* taking average of each color component axis of cube.  But   */
  548. /* instead ... Use the Average color computed earlier for each */
  549. /* cube! (This is more accurate color).  Multiply by two to    */
  550. /* scale the 5 bit color into the 6 bit palette entry.         */
  551. /*.............................................................*/
  552.   for(i=0;i < num_cubes;i++)
  553.     {
  554.       color_array[3*i+0] = 2*CUBE_LIST[i].r_avg;
  555.       color_array[3*i+1] = 2*CUBE_LIST[i].g_avg;
  556.       color_array[3*i+2] = 2*CUBE_LIST[i].b_avg;
  557.     }
  558. /*.............................................................*/
  559. /*          Set unused palette entries to black.               */
  560. /*.............................................................*/
  561.   for(i=num_cubes;i<256;i++)
  562.     {
  563.       color_array[3*i+0] = 0;
  564.       color_array[3*i+1] = 0;
  565.       color_array[3*i+2] = 0;
  566.     }
  567.   assign_lut_to_colors(array,num_cubes);
  568.   return 256;
  569. }                        /*.....  End move_cubes_to_lut  ......*/
  570.  
  571.  
  572. /*................. ASSIGN_LUT_TO_COLORS ........... 6-3-94 ...*/
  573. /* Assign each of the 32768 color values in the RGB Color Space*/
  574. /* (compressed from 16M) to one of the up to 256 cubes (which  */
  575. /* map to the color lut). 'ADPTV_ASSIGN_MODE' determines the   */
  576. /* way that colors are assigned.  If '0', then color error is  */
  577. /* minimized. Otherwise, all colors which land within a cube   */
  578. /* get set to cube average color.                              */
  579. /*.............................................................*/
  580. void  assign_lut_to_colors(unsigned char *array,unsigned
  581.                                                      num_cubes)
  582. {
  583.   int red,grn,blu,dr,dg,db,error,last_error;
  584.   unsigned i,j,k,n;
  585.   long index,index0;
  586.   if(!ADPTV_ASSIGN_MODE)
  587. /*.............................................................*/
  588. /*  For each color in the image, assign it the CUBE ID for the */
  589. /* CUBE which has the nearest average color value .            */
  590. /*.............................................................*/
  591.     {
  592.       for(i=0;i<32768;i++)
  593.         {
  594.           if(array[i] != 0)
  595.             {
  596.               red = (i & 0x7c00) >> 10;
  597.               grn = (i & 0x03e0) >>  5;
  598.               blu =  i & 0x001f       ;
  599.               last_error = 10000;
  600.               for(n=0;n<num_cubes;n++)
  601.                 {
  602.                   dr = CUBE_LIST[n].r_avg - red;
  603.                   dg = CUBE_LIST[n].g_avg - grn;
  604.                   db = CUBE_LIST[n].b_avg - blu;
  605.                   error = dr*dr+dg*dg+db*db;
  606.                   if(error <= last_error)
  607.                     {
  608.                       array[i] = n;
  609.                       last_error = error;
  610.                     }
  611.                 }
  612.             }
  613.         }
  614.     }
  615. /*.............................................................*/
  616. /* For each cube, assign its ID to all of the colors in        */
  617. /* its boundary. This method is not as accurate as the one     */
  618. /* above but its faster.                                       */
  619. /*.............................................................*/
  620.   else
  621.     {
  622.       for(n=0;n<num_cubes;n++)
  623.         {
  624.           for(k=CUBE_LIST[n].x0;k<CUBE_LIST[n].x1;k++)
  625.             {
  626.               index0 = k<<10;
  627.               for(j=CUBE_LIST[n].y0;j<CUBE_LIST[n].y1;j++)
  628.                 {
  629.                   index = index0 + (j<<5) + CUBE_LIST[n].z0;
  630.                   for(i=CUBE_LIST[n].z0;i<CUBE_LIST[n].z1;i++)
  631.                     {
  632.                       array[index] = n;
  633.                       index ++;
  634.                     }
  635.                 }
  636.             }
  637.         }
  638.     }
  639.   return;
  640. }                         /*.... END: assign_lut_to_colors ....*/
  641.  
  642.  
  643. /*..................... VALIDATE_CUBE ............ 1-12-94 ....*/
  644. /* Insures that cube point 0 is closer to (or same distance    */
  645. /* from) origin of RGB Color than cube point 1.                */
  646. /*.............................................................*/
  647. void  validate_cube(struct CUBE *pcube)
  648. {
  649.   unsigned temp;
  650.   if(pcube->x0 > pcube->x1)
  651.     {
  652.       temp = pcube->x0;
  653.       pcube->x0 = pcube->x1;
  654.       pcube->x1 = temp;
  655.     }
  656.   if(pcube->y0 > pcube->y1)
  657.     {
  658.       temp = pcube->y0;
  659.       pcube->y0 = pcube->y1;
  660.       pcube->y1 = temp;
  661.     }
  662.   if(pcube->z0 > pcube->z1)
  663.     {
  664.       temp = pcube->z0;
  665.       pcube->z0 = pcube->z1;
  666.       pcube->z1 = temp;
  667.     }
  668.   return;
  669. }                                 /*.... END: validate_cube ...*/
  670.  
  671. /*........................... COPY_CUBE .......... 1-15-94 ....*/
  672. /* This routine copies the 'cube' struct to the 'new_cube'     */
  673. /* struct.                                                     */
  674. /*.............................................................*/
  675. void  copy_cube(struct CUBE cube,struct CUBE *pnew_cube)
  676. {
  677.   pnew_cube->x0 = cube.x0;
  678.   pnew_cube->y0 = cube.y0;
  679.   pnew_cube->z0 = cube.z0;
  680.   pnew_cube->x1 = cube.x1;
  681.   pnew_cube->y1 = cube.y1;
  682.   pnew_cube->z1 = cube.z1;
  683.   pnew_cube->vol = cube.vol;
  684.   pnew_cube->r_avg = cube.r_avg;
  685.   pnew_cube->g_avg = cube.g_avg;
  686.   pnew_cube->b_avg = cube.b_avg;
  687.   pnew_cube->fsum  = cube.fsum;
  688.   pnew_cube->cerr  = cube.cerr;
  689.   pnew_cube->fom  = cube.fom;
  690.   return;
  691. }                                 /*....   END: copy_cube  ....*/
  692.  
  693.  
  694. /*..................... ADD_CUBE_TO_LIST ........... 6-1-94 ...*/
  695. /* Adds a cube to list.  Inserts cube appropriately to maintain*/
  696. /* a descending cube sort based on CUBE_LIST[i].fom.  In       */
  697. /* otherwords, CUBE_LIST[0].fom is always going to be the      */
  698. /* largest value of all cubes.  Give this routine a cube and   */
  699. /* the current number of cubes in the list 'n'. Routine returns*/
  700. /* the new value of 'n'.  NOTE: For n cubes, you have          */
  701. /* CUBE_LIST[0] thru CUBE_LIST[n-1].                           */
  702. /*.............................................................*/
  703. int  add_cube_to_list(struct CUBE new_cube,int n)
  704. {
  705.   int m;
  706.   m = n+1;
  707. /*.............................................................*/
  708. /* Bump lower FOM valued cubes down a step in cube list.       */
  709. /*.............................................................*/
  710.   if(n>0)
  711.     while(CUBE_LIST[n-1].fom <= new_cube.fom)
  712.       {
  713.         CUBE_LIST[n].x0 = CUBE_LIST[n-1].x0;
  714.         CUBE_LIST[n].y0 = CUBE_LIST[n-1].y0;
  715.         CUBE_LIST[n].z0 = CUBE_LIST[n-1].z0;
  716.         CUBE_LIST[n].x1 = CUBE_LIST[n-1].x1;
  717.         CUBE_LIST[n].y1 = CUBE_LIST[n-1].y1;
  718.         CUBE_LIST[n].z1 = CUBE_LIST[n-1].z1;
  719.         CUBE_LIST[n].vol = CUBE_LIST[n-1].vol;
  720.         CUBE_LIST[n].r_avg = CUBE_LIST[n-1].r_avg;
  721.         CUBE_LIST[n].g_avg = CUBE_LIST[n-1].g_avg;
  722.         CUBE_LIST[n].b_avg = CUBE_LIST[n-1].b_avg;
  723.         CUBE_LIST[n].fsum = CUBE_LIST[n-1].fsum;
  724.         CUBE_LIST[n].cerr = CUBE_LIST[n-1].cerr;
  725.         CUBE_LIST[n].fom = CUBE_LIST[n-1].fom;
  726.         n--;
  727.         if(n==0) break;
  728.       }
  729. /*.............................................................*/
  730. /*                  Add new cube to cube list.                 */
  731. /*.............................................................*/
  732.   CUBE_LIST[n].x0 = new_cube.x0;
  733.   CUBE_LIST[n].y0 = new_cube.y0;
  734.   CUBE_LIST[n].z0 = new_cube.z0;
  735.   CUBE_LIST[n].x1 = new_cube.x1;
  736.   CUBE_LIST[n].y1 = new_cube.y1;
  737.   CUBE_LIST[n].z1 = new_cube.z1;
  738.   CUBE_LIST[n].vol = new_cube.vol;
  739.   CUBE_LIST[n].r_avg = new_cube.r_avg;
  740.   CUBE_LIST[n].g_avg = new_cube.g_avg;
  741.   CUBE_LIST[n].b_avg = new_cube.b_avg;
  742.   CUBE_LIST[n].fsum = new_cube.fsum;
  743.   CUBE_LIST[n].cerr = new_cube.cerr;
  744.   CUBE_LIST[n].fom = new_cube.fom;
  745.   return m;
  746. }                                 /*.. END: add_cube_to_list ..*/
  747.  
  748.  
  749. /*................... DELETE_CUBE_FROM_LIST ...... 1-15-94 ....*/
  750. /* Deletes cube 'p' from cube list. Bumps up remaining cubes to*/
  751. /* keep list consecutive and hole free.  Give this routine the */
  752. /* current number of cubes in list ('n') and the cube id to be */
  753. /* deleted ('p').  Routine returns the new value of 'n'.       */
  754. /* NOTE: For n cubes, you have CUBE_LIST[0] thru CUBE_LIST[n-1]*/
  755. /*.............................................................*/
  756. int  delete_cube_from_list(int p,int n)
  757. {
  758.   if(p >= n)
  759.     return n;
  760.   while(p < n-1)
  761.     {
  762.       CUBE_LIST[p].x0 = CUBE_LIST[p+1].x0;
  763.       CUBE_LIST[p].y0 = CUBE_LIST[p+1].y0;
  764.       CUBE_LIST[p].z0 = CUBE_LIST[p+1].z0;
  765.       CUBE_LIST[p].x1 = CUBE_LIST[p+1].x1;
  766.       CUBE_LIST[p].y1 = CUBE_LIST[p+1].y1;
  767.       CUBE_LIST[p].z1 = CUBE_LIST[p+1].z1;
  768.       CUBE_LIST[p].vol = CUBE_LIST[p+1].vol;
  769.       CUBE_LIST[p].r_avg = CUBE_LIST[p+1].r_avg;
  770.       CUBE_LIST[p].g_avg = CUBE_LIST[p+1].g_avg;
  771.       CUBE_LIST[p].b_avg = CUBE_LIST[p+1].b_avg;
  772.       CUBE_LIST[p].fsum  = CUBE_LIST[p+1].fsum;
  773.       CUBE_LIST[p].cerr  = CUBE_LIST[p+1].cerr;
  774.       CUBE_LIST[p].fom  = CUBE_LIST[p+1].fom;
  775.       p++;
  776.     }
  777.   return n-1;
  778. }                            /*.. END: delete_cube_from_list ..*/
  779.  
  780. /*..................... REPLACE_PIXEL.C ............ 6-1-94 ...*/
  781. /*  This routine compresses the 3 byte per pixel data in the   */
  782. /*  array 'byte_buf' into a single byte per pixel data array   */
  783. /*  (back into 'byte_buf'). The 8-8-8 RGB pixel is down        */
  784. /*  converted to a 5-5-5 RGB pixel.  Then, the 15 bit RGB      */
  785. /*  pixel value is used to look up in the 'array' to get the 8 */
  786. /*  bit palette index for that color. The number of pixels in  */
  787. /*  'byte_buf' is defined by 'width'.                          */
  788. /*.............................................................*/
  789. void replace_pixel(unsigned char *byte_buf,unsigned 
  790. width,unsigned char *array)
  791. {
  792.   int i,sum;
  793. /*.............................................................*/
  794. /* If Adaptive Palette ON, map pixel to adaptive palette.      */
  795. /*.............................................................*/
  796.   if(ADPTV_MODE)
  797.     for(i=0;i<width;i++)
  798.       {
  799.         sum = 0;
  800.         sum += (byte_buf[3*i+2])/8 << 10;            /* RED    */
  801.         sum += (byte_buf[3*i+1])/8 << 5;             /* GREEN  */
  802.         sum += (byte_buf[3*i]  )/8;                  /* BLUE   */
  803.         byte_buf[i] = array[sum];
  804.       }
  805. /*.............................................................*/
  806. /* If Adaptive Palette OFF, map pixel to 8 bit RGB palette.    */
  807. /*.............................................................*/
  808.   else
  809.     for(i=0;i<width;i++)
  810.       {
  811.         sum = 0;
  812.         sum += (byte_buf[3*i+2])/32 << 5;            /* RED    */
  813.         sum += (byte_buf[3*i+1])/32 << 2;            /* GREEN  */
  814.         sum += (byte_buf[3*i]  )/64;                 /* BLUE   */
  815.         byte_buf[i] = (unsigned char) sum;
  816.       }
  817.   return;
  818. }                    /*.....        End replace_pixel    ......*/
  819.  
  820.  
  821.  
  822. /*................ SET_ADAPTIVE_CONFIG ........... 4-30-94 ....*/
  823. /* This routine configures the operation of the TIFF256 library*/
  824. /* with regards to 24 bit/pixel images.  The input parameters  */
  825. /* have are:                                                   */
  826. /*                                                             */
  827. /*          enable - Adaptive Palette is enabled when enable   */
  828. /*                   is 1. disabled otherwise.                 */
  829. /*      num_colors - This parameter determines how many colors */
  830. /*                   the 16M color image will be reduced to.   */
  831. /*                   (2 min, 256 max!)                         */
  832. /*         quality - This parameter lets the user optimize the */
  833. /*                   Adaptive Palette algorithm for image      */
  834. /*                   quality. The valid range is from 0 to 100.*/
  835. /*                     For values closer to 0, the algorithm is*/
  836. /*                   optimized for images with fewer colors,   */
  837. /*                   but many shades per color (smooth shading */
  838. /*                   is emphasized at the expense of color     */
  839. /*                   variety).                                 */
  840. /*                     For values closer to 100, the algorithm */
  841. /*                   is optimized for images with a broader    */
  842. /*                   color distribution (many colors are       */
  843. /*                   accomodated at the expense of shade       */
  844. /*                   continuity).                              */
  845. /*.............................................................*/
  846. void  set_adaptive_config(int enable,int num_colors,int quality)
  847. {
  848.   ADPTV_MODE         = enable;
  849.   ADPTV_NUM_COLORS   = num_colors;
  850.   ADPTV_QUALITY      = quality;
  851.   if(ADPTV_NUM_COLORS > 256) ADPTV_NUM_COLORS = 256;
  852.   if(ADPTV_NUM_COLORS < 2)   ADPTV_NUM_COLORS = 2;
  853.   if(ADPTV_QUALITY > 100) ADPTV_QUALITY = 100;
  854.   return;
  855. }
  856.  
  857. /*................. GET_ADAPTIVE_CONFIG ............ 4-10-94 ..*/
  858. /*  This routine returns the current Adaptive Palette          */
  859. /* configuration parameters (which were set by                 */
  860. /* set_adaptive_config().                                      */
  861. /*.............................................................*/
  862. void  get_adaptive_config(int *penable,int *pnum_colors,
  863.                           int *pquality)
  864. {
  865.   *penable      = ADPTV_MODE;
  866.   *pnum_colors  = ADPTV_NUM_COLORS;
  867.   *pquality     = ADPTV_QUALITY;
  868.   return;
  869. }
  870.  
  871. /*.................... TRUE_COLOR_LUT.C .......... 5-15-94 ....*/
  872. /* This routine generates a 'true color' LUT.  An 8 bit index  */
  873. /* into the LUT represents 3 bits of RED, 3 bits of GREEN, and */
  874. /* 2 bits of BLUE.  The 3 msbs of the 8 bit index are the RED  */
  875. /* field, next 3 are GREEN, and the 2 lsbs are the BLUE field. */
  876. /*                                                             */
  877. /*.............................................................*/
  878. void true_color_lut(void)
  879. {
  880.   int i;
  881.   unsigned char color_array[768];
  882.   for(i=0;i<256;i++)
  883.     {
  884.       color_array[3*i+0]= ((i & 0x00e0) >> 5) * 9;
  885.       color_array[3*i+1]= ((i & 0x001c) >> 2) * 9;
  886.       color_array[3*i+2]= (i & 0x0003) * 21;
  887.     }
  888.   vsa_write_color_block(0,256,color_array);
  889.   return;
  890. }                          /*.....   End true_color_lut   .....*/
  891.